package com.brillilab.starter.handler;

import com.brillilab.common.constant.ClientTypeEnum;
import com.brillilab.common.constant.ResultEnum;
import com.brillilab.common.entity.ResponseVo;
import com.brillilab.common.rocketmq.OnsProducer;
import com.brillilab.common.rocketmq.UserLogVo;
import com.brillilab.common.utils.DateUtil;
import com.brillilab.domain.enums.lab.LabMemberPowerEnum;
import com.brillilab.domain.po.lab.LabMemberPower;
import com.brillilab.domain.vo.crm.CrmUsersInfoVo;
import com.brillilab.domain.vo.user.UserInfoVo;
import com.brillilab.service.logic.crm.CrmUsersLogic;
import com.brillilab.service.logic.user.UsersLogic;
import com.brillilab.starter.constant.StarterConstant;
import com.brillilab.starter.utils.RespOutWithUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author LJ
 * @ClassName: PowerInterceptor
 * @Description: 权限校验拦截器
 * @date 2018年3月9日 下午4:35:06
 */
@Slf4j
public class PowerInterceptor implements HandlerInterceptor {

    @Autowired
    private UsersLogic usersLogic;
    @Autowired
    private CrmUsersLogic crmUsersLogic;
    @Resource
    private OnsProducer onsProducer;

    /**
     * 在请求处理之前进行调用（Controller方法调用之前）
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        String token = request.getHeader(StarterConstant.TOKEN);
        if (StringUtils.isBlank(token)) {
            RespOutWithUtil.outWithJson(response, ResultEnum.USER_NOT_LOGIN, null);
            return false;
        }
        // 获取用户登录信息
        String client = token.split("_")[0];

        //crm 登录临时处理
        if (client.equals(ClientTypeEnum.CRM.getValue())) {
            CrmUsersInfoVo crmUserByToken = crmUsersLogic.getCrmUserByToken(token);
            if (crmUserByToken != null) {
                return true;
            }
        }
        //正式Token
        UserInfoVo userVo = usersLogic.getUserByToken(token);
        if (userVo == null) {
            String message = null;
            if (token.startsWith(ClientTypeEnum.PC.getValue())) {
                message = "由于您长时间未操作，请重新登陆！";
            }
            RespOutWithUtil.outWithJson(response, ResultEnum.USER_NOT_LOGIN, message);
            return false;
        }
        // 请求路径
        String servletPath = request.getServletPath();
//        log.info(">>>>>> 请求路径 " + servletPath + "  labMemberId：" + userVo.getLabMemberId());
        this.sendUserLogMq(userVo, servletPath, token);
        //提示前端要刷新用户信息
        // todo 优化
        ResponseVo refreshUser = usersLogic.getRefreshUser(userVo, token);
        if (refreshUser != null) {
            response.setIntHeader("Refresh-Code", refreshUser.getCode());
            response.setHeader("Refresh-Message", URLEncoder.encode(refreshUser.getMessage(), "UTF-8"));
            response.setHeader("Access-Control-Expose-Headers ", "Refresh-Code,Refresh-Message");
            return true;
        }
        // 验证权限
        return this.hasPower(response, handler, userVo);
    }

    //发送用户访问日志队列
    private void sendUserLogMq(UserInfoVo userVo, String path, String token) {
        try {
            UserLogVo userLogVo = new UserLogVo();
            int firstIndex = path.indexOf("/", 1);
            int index = path.indexOf("/", firstIndex + 1);
            LocalDateTime now = LocalDateTime.now();
            userLogVo.setUserId(userVo.getId());
            userLogVo.setUserName(userVo.getName());
            userLogVo.setLabId(userVo.getLabId());
            userLogVo.setUserPayType(userVo.getUserPayType());
            userLogVo.setYear(now.getYear());
            userLogVo.setMonth(now.getMonthValue());
            userLogVo.setDay(now.getDayOfMonth());
            userLogVo.setHour(now.getHour());
            userLogVo.setAccessTime(DateUtil.fromLocalDateTime(now));
            userLogVo.setClientType(token.substring(0, token.indexOf("_")));
            userLogVo.setFirstUrl(path.substring(0, index));
            userLogVo.setSecondUrl(path.substring(index));
            userLogVo.setPiIsLogin(userVo.getPiFirstLoginTime() == null ? 0 : 1);
            userLogVo.setIsPi(userVo.getIsOwner());
            onsProducer.sendClusteringUserLog(userLogVo);
        } catch (Exception e) {
            log.error("log send to queue error " + e.getMessage());
        }
    }

    /**
     * 判断是否有权限
     *
     * @param handler
     * @return
     */
    private boolean hasPower(HttpServletResponse response, Object handler, UserInfoVo userVo) {
        // 判断是否是实验室管理员
        if (userVo.getId().equals(userVo.getOwnerId())) {
            return true;
        }
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            // 获取方法上的注解
            RequestPower requestPower = handlerMethod.getMethod().getAnnotation(RequestPower.class);
            // 如果方法上的注解为空 则获取类的注解
            if (requestPower == null) {
                requestPower = handlerMethod.getMethod().getDeclaringClass().getAnnotation(RequestPower.class);
            }
            // 如果标记了注解，则判断权限
            if (requestPower != null && StringUtils.isNotBlank(requestPower.value())) {
                List<LabMemberPower> powerList = userVo.getPowers();
                if (powerList != null && powerList.size() > 0) {
                    // 判断是否有权限
                    for (LabMemberPower labMemberPower : powerList) {
                        if (requestPower.value().equals(labMemberPower.getPower())) {
                            return true;
                        }
                    }
                }
                String message = "暂无" + LabMemberPowerEnum.Power.getKey(requestPower.value()) + "权限,请联系管理员！";
                RespOutWithUtil.outWithJson(response, ResultEnum.USER_NOT_POWER, message);
                return false;
            }

        }
        return true;
    }

    /**
     * 请求处理之后进行调用，但是在视图被渲染之前（Controller方法调用之后）
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {

    }

    /**
     * 在整个请求结束之后被调用，也就是在DispatcherServlet 渲染了对应的视图之后执行（主要是用于进行资源清理工作）
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
    }

}
